package com.qall.media;

import org.opencv.core.Point;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Random;

/**
 * 一些openCv 分装工具方法
 */
@Service
public class OpenCvUtil {

    @Value("${opencv.pic.prefix}")
    private String openCvPrefix;

    public Mat picGrey(Mat mat) {
        int col = mat.width();
        int rol = mat.height();
        for (int i = 0; i < rol; i++) {
            for (int j = 0; j < col; j++) {
                // 获取 i j点的像素
                double[] point = mat.get(i, j);
                double av = sum(point) / 3;
                // 设置点 i j 的像素
                mat.put(i, j, av, av, av);
            }
        }
        return mat;
    }

    /**
     * 1  12 互换 2 13互换 2 23互换  4 13互换
     * 通道互换
     *
     * @param mat
     * @return
     */
    public Mat channelSwitch(Mat mat, int type) {
        int col = mat.width();
        int rol = mat.height();
        for (int i = 0; i < rol; i++) {
            for (int j = 0; j < col; j++) {
                // 获取 i j点的像素
                double[] point = mat.get(i, j);
                double a = 0, b = 0, c = 0;
                if (type == 1) {
                    c = point[2];
                    a = point[1];
                    b = point[0];
                } else if (type == 2) {
                    a = point[2];
                    b = point[1];
                    c = point[0];
                } else if (type == 3) {
                    a = point[0];
                    b = point[2];
                    c = point[1];
                } else if (type == 4) {
                    a = point[2];
                    b = point[1];
                    c = point[0];
                }

                // 设置点 i j 的像素
                mat.put(i, j, a, b, c);
            }
        }
        return mat;
    }


    /**
     * 1 blue  2 green  3 red
     * 1 1    2 2     3 3      4 :12 5:13 6:23 7:123
     * 删除通道
     *
     * @param mat
     * @param type
     * @return
     */
    public Mat channelRemove(Mat mat, int type) {
        int col = mat.width();
        int rol = mat.height();
        for (int i = 0; i < rol; i++) {
            for (int j = 0; j < col; j++) {
                // 获取 i j点的像素
                double[] point = mat.get(i, j);
                double a = 0, b = 0, c = 0;
                if (type == 1) {
                    a = 0;
                    b = point[1];
                    c = point[2];
                } else if (type == 2) {
                    a = point[0];
                    b = 0;
                    c = point[2];
                } else if (type == 3) {
                    a = point[0];
                    b = point[1];
                    c = 0;
                } else if (type == 4) {
                    a = point[0];
                    b = point[1];
                    c = 0;
                } else if (type == 5) {
                    a = 0;
                    b = 0;
                    c = point[2];
                } else if (type == 6) {
                    a = point[0];
                    b = 0;
                    c = 0;
                } else if (type == 7) {
                    a = 0;
                    b = 0;
                    c = 0;
                }

                // 设置点 i j 的像素
                mat.put(i, j, a, b, c);
            }
        }
        return mat;
    }


    public double sum(double[] params) {
        double ret = 0;
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                ret += params[i];
            }
        }

        return ret;
    }

    //旋转
    public Mat rotate(Mat src, double angle) {
        Point center = new Point(src.cols() / 2, src.rows() / 2);
        //double angle=60;//旋转角度
        double scale = 1;//缩放尺度
        Mat mat = Imgproc.getRotationMatrix2D(center, angle, scale);
        Imgproc.warpAffine(src, mat, mat, src.size());
        return mat;
    }

    //平移
    public Mat move(Mat src, double x, double y) {
        Mat mat = new Mat(2, 3, CvType.CV_32FC1);
        mat.put(0, 0, new double[]{1, 0, x, 0, 1, y});
        Mat m = src;
        Imgproc.warpAffine(src, mat, mat, src.size());
        return mat;
    }

    //缩放
    public Mat scale(Mat src, double scale) {
        Point center = new Point(src.cols() / 2, src.rows() / 2);
        double angle = 0;//旋转角度
        //double scale=0.6;//缩放尺度
        Mat mat = Imgproc.getRotationMatrix2D(center, angle, scale);
        Imgproc.warpAffine(src, mat, mat, src.size());
        return mat;
    }

    /**
     * 识别人脸在图片中的位置矩阵列表
     *
     * @param src
     * @return
     */
    public Rect[] faceRect(Mat src) {
        MatOfRect faceDetections = new MatOfRect();
        CascadeClassifier faceDetector = new CascadeClassifier("D:\\Program Files\\opencv\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
        faceDetector.detectMultiScale(src, faceDetections);
        Rect[] rects = faceDetections.toArray();
        return rects;
    }

    public double compare_image(Mat mat_1, Mat mat_2) {
        // CORREL 相关系数
        Mat hist_1 = new Mat();
        Mat hist_2 = new Mat();

        //颜色范围
        MatOfFloat ranges = new MatOfFloat(0f, 256f);
        //直方图大小， 越大匹配越精确 (越慢)
        MatOfInt histSize = new MatOfInt(1000);

        
        Imgproc.calcHist(Arrays.asList(mat_1), new MatOfInt(0), new Mat(), hist_1, histSize, ranges);
        Imgproc.calcHist(Arrays.asList(mat_2), new MatOfInt(0), new Mat(), hist_2, histSize, ranges);

        // CORREL 相关系数
        double res = Imgproc.compareHist(hist_1, hist_2, Imgproc.CV_COMP_CORREL);
        return res;
    }


    public BufferedImage Mat2BufImg(Mat matrix, String fileExtension) {
        // convert the matrix into a matrix of bytes ap propriate for
        // this file extension
        MatOfByte mob = new MatOfByte();
        Imgcodecs.imencode(fileExtension, matrix, mob);
        // convert the "matrix of bytes" into a byte array
        byte[] byteArray = mob.toArray();
        BufferedImage bufImage = null;
        try {
            InputStream in = new ByteArrayInputStream(byteArray);
            bufImage = ImageIO.read(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bufImage;
    }

    public Mat subMat(Mat mat, Rect rect) {
        return mat.submat(rect.y, rect.y + rect.height, rect.x, rect.x + rect.width);
    }

    /**
     * BufferedImage转换成Mat
     *
     * @param original 要转换的BufferedImage
     * @param imgType  bufferedImage的类型 如 BufferedImage.TYPE_3BYTE_BGR
     * @param matType  转换成mat的type 如 CvType.CV_8UC3
     */
    public Mat BufImg2Mat(BufferedImage original, int imgType, int matType) {
        if (original == null) {
            throw new IllegalArgumentException("original == null");
        }

        // Don't convert if it already has correct type
        if (original.getType() != imgType) {

            // Create a buffered image
            BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);

            // Draw the image onto the new buffer
            Graphics2D g = image.createGraphics();
            try {
                g.setComposite(AlphaComposite.Src);
                g.drawImage(original, 0, 0, null);
            } finally {
                g.dispose();
            }
        }
        DataBufferByte dbi = (DataBufferByte) original.getRaster().getDataBuffer();
        byte[] pixels = dbi.getData();
        Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);
        mat.put(0, 0, pixels);
        return mat;
    }

    public File matToFile(Mat mat) {
        long randomInt = new Random().nextInt();
        String fileName = randomInt + ".png";
        String path = openCvPrefix + fileName;
        Imgcodecs.imwrite(path, mat);
        File file = new File(path);
        return file;
    }


}
